Saving Data to Files
Steven Cen
Introduction
This tutorial will teach you how to get data to persist when you close the app and such. For example, for a game, you may want to save the highest score in a file, or for a drawing app, you may want to save pictures the user draws.
The two ways to store data with persistence that are discussed in this tutorial are onto the internal storage and external storage. However, there are other methods including saving primitive data with SharedPreferences and managing more complex data with MySQL but they won’t be taught here.
Internal Storage
Each application on your device has its own private directory which only it has access to (unless you specify otherwise). Internal storage is always available for access, and when you uninstall the app, the app’s data in the internal storage is also deleted.
Create a new project with MainActivity.java and activity_main.xml as the layout file.
In activity_main.xml, add the following code.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:textSize="30dp"
android:layout_margin="20dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="ENTER TEXT"
android:gravity="center"/>
<EditText
android:id="@+id/textbox"
android:gravity="top"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"/>
<Button android:id="@+id/write_internal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Write to Internal Storage"
android:onClick="writeToInternal" />
<Button android:id="@+id/read_internal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Read the Internal Storage"
android:onClick="readInternal"/>
<TextView
android:id="@+id/display_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:layout_margin="20dp"/>
</LinearLayout>
Your layout should look something like this:
In your MainActivity class, define the following variables/handles and change onCreate to this:
final String FILE_NAME = "nameMeWhatYouWant.txt";//name of the file to write/save data to
TextView displayText;
EditText textBoxEdit;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
displayText = (TextView) findViewById(R.id.display_text);
textBoxEdit = (EditText) findViewById(R.id.textbox);
}
The two buttons in your layout file have android:onClick properties, so implement them like so:
// Write to the file by taking the text from your EditText
public void writeToInternal(View v) {
try {
OutputStreamWriter out = new OutputStreamWriter(openFileOutput(FILE_NAME, Context.MODE_PRIVATE)); // Context.MODE_PRIVATE denotes that this file to write to is accessible only by the application itself, stored in some designated directory in your device’s internal storage
out.write(textBoxEdit.getText().toString());
out.close();
Toast.makeText(this, "Successfully wrote to " + FILE_NAME, Toast.LENGTH_LONG).show();
} catch (Exception e) {
e.printStackTrace();
}
}
//Read from the file and spit it out onto the TextView
public void readInternal (View v) {
try {
InputStream inputStream = openFileInput(FILE_NAME);
if (inputStream != null) { // make sure file exists/is openable
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String str;
StringBuilder strBuf = new StringBuilder();
while ((str = bufferedReader.readLine()) != null) {
strBuf.append(str + "\n"); // append the new line that you read
}
inputStream.close();
displayText.setText(strBuf.toString());
}
} catch (java.io.FileNotFoundException e) {
//If you haven't created the file, you can't read from it. Thus you should get this error if so.
} catch (Exception e) {
e.printStackTrace();
}
}
External Storage
Files saved onto external storage are accessible by any application and are not deleted when you delete the application which saved that file. When you connect your device to your computer and mount your phone as a USB storage device, you will get to browse the external storage of your device on your computer. Other external storage devices include SD cards. But your phone might not have an SD card, so it will emulate one.
To access the external storage, the application needs special permission. So go to your manifest and put the following xml tag into the file as a direct child of <manifest>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Now change your layout code to the following:
<ScrollView
android:layout_height="fill_parent"
android:layout_width="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView
android:textSize="30dp"
android:layout_margin="20dp"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="ENTER TEXT"
android:gravity="center"/>
<EditText
android:id="@+id/textbox"
android:gravity="top"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"/>
<Button android:id="@+id/write_internal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Write to Internal Storage"
android:onClick="writeToInternal" />
<Button android:id="@+id/read_internal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Read the Internal Storage"
android:onClick="readInternal"/>
<Button
android:id="@+id/write_external"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Write to External Storage"
android:layout_marginTop="30dp"/>
<Button
android:id="@+id/read_external"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Read the External Storage" />
<TextView
android:id="@+id/display_text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="16sp"
android:layout_margin="20dp"/>
</LinearLayout>
</ScrollView>
Your screen should now look something like this:
Add the following variables definitions to the class:
// The directory for your device’s external storage
final String externalStorage = Environment.getExternalStorageDirectory().getPath();
// Name of the folder you are going to create in the external storage
String folderName = "WowIHaveMyOwnFolder";
// A folder is a file too, and you need to make the directory with code later
File folder = new File(externalStorage, folderName);
Implement the onClick button functions with the following:
public void writeToExternal(View v) {
//Create new folder called WowIHaveMyOwnFolder
if (!folder.exists()) { // if folder doesn't exist
boolean xx = folder.mkdirs();//”make a directory” that uses the file’s name that you declared earlier
Toast.makeText(this, String.valueOf(xx), Toast.LENGTH_SHORT).show();
}
try {
File myFile = new File(externalStorage+"/"+folderName, FILE_NAME+".txt");
myFile.createNewFile();
FileOutputStream fileOutputStream = new
FileOutputStream(myFile);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream);
//Write to file
outputStreamWriter.append(textBoxEdit.getText().toString());
outputStreamWriter.close();
fileOutputStream.close();
Toast.makeText(getApplicationContext(), FILE_NAME + " saved.",Toast.LENGTH_LONG).show();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
public void readExternal(View v) {
String line = "";
StringBuilder stringBuilder = new StringBuilder();
try {
File myFile = new File(externalStorage+"/"+folderName, FILE_NAME+".txt");
FileInputStream fileInputStream = new FileInputStream(myFile);
BufferedReader myReader = new BufferedReader(new InputStreamReader(fileInputStream));
while ((line = myReader.readLine()) != null) {
stringBuilder.append(line + "\n");
}
myReader.close();
} catch (Exception e) {
e.printStackTrace();
}
displayText.setText(stringBuilder.toString());
}
Although we are writing to external storage with the same FILE_NAME for the name of the file we are saving, keep in mind that the internal and external files are completely unrelated and just share the same name for convenience in this tutorial.
If you read and write to a file, you should get something like the following:
If you write to external storage and you plug your phone into your computer as a media device, you can view the external storage directories and you should see the folder made with the file you made in it!